/*-*-C-*-
 *
 * Generate #include header file from a document
 */

#include "resed.h"


/*
 * Interpolate the % escape sequences.  %% means a single %.
 */

static void interpolate (char *line, char *patt, char *wname, char *iname, char *tag, int number)
{
    char c;

    while ((c = *patt++) != 0)
    {
        if (c == '%')
        {
            c = *patt++;
            switch (c)
            {
            case 'w':
                strcpy (line, wname);
                line += strlen (line);
                break;
            case 'n':
                strcpy (line, iname);
                strcat (line, tag);
                line += strlen (line);
                break;
            case 'i':
                sprintf (line, "%d", number);
                line += strlen (line);
                break;
            case 'x':
                sprintf (line, "%x", number);
                line += strlen (line);
                break;
            default:
                *line++ = c;
                break;
            }
        }
        else
        {
            *line++ = c;
        }
    }
    *line++ = 0;
}


static char * doline (char *line, char *buf, int *nbytes)
{
    int n = strlen (line);
    *nbytes += n + 1;
    if (buf)
    {
        memcpy (buf, line, n);
        buf += n;
        *buf++ = '\n';
    }
    return buf;
}


/*
 * If buf, fill it in.  If buf == NULL, count size needed for
 * buf, and return it.
 *
 * patt is the pattern to use when generating the line.  It
 * can have the following escapes:-
 *   %w - window name; %n - item name; %i - decimal icon number;
 *   %x - hex icon number.
 */

static int count_or_write (DocumentPtr doc, char *buf, char *patt)
{
    ResourcePtr res;
    int i;
    char rname[100], iname[100], *s, *t;
    char line[256];
    int nbytes = 0;

    for (res = doc->resources; res; res = res->next)
    {
        Bool any = FALSE;
        if (res->name[0] == 0)
            continue;           /* Skip unnamed resources */

        for (t = rname, s = res->name; (*t++ = toupper(*s++)) != 0;)
            ;
        
        for (i = 0; i < res->numicons; i++)
        {
            IconInfoPtr icon = res->icons + i;
            ItemInfoPtr item = icon->owner;
            if (item == NULL)
                continue;       /* deleted */
            if (item->u.master != i)
                continue;       /* not master */
            if (item->name[0] == 0)
                continue;       /* anonymous */

            any = TRUE;

            for (t = iname, s = item->name; (*t++ = toupper(*s++)) != 0;)
                ;
        
            switch (item->type)
            {
            case SimpleIcon:
            case CommandButton:
            case Label:
            case DisplayField:
            case WriteableField:
            case OptionButton:
            case RadioButton:
            case MenuButton:
                interpolate (line, patt, rname, iname, "", i);
/*              sprintf (line, "#define I_%s_%s %d\n",rname, iname, i);*/
                buf = doline (line, buf, &nbytes);
                break;
            case HSlider:
            case VSlider:
                interpolate (line, patt, rname, iname, "_WELL", item->u.slider.well);
/*              sprintf (line, "#define I_%s_%s_WELL %d\n",rname, iname, item->u.slider.well);*/
                buf = doline (line, buf, &nbytes);
                interpolate (line, patt, rname, iname, "_TRACK", item->u.slider.track);
/*              sprintf (line, "#define I_%s_%s_TRACK %d\n",rname, iname, item->u.slider.track);*/
                buf = doline (line, buf, &nbytes);
                interpolate (line, patt, rname, iname, "_KNOB", item->u.slider.knob);
/*              sprintf (line, "#define I_%s_%s_KNOB %d\n",rname, iname, item->u.slider.knob);*/
                buf = doline (line, buf, &nbytes);
                break;
            case GroupBox:
                interpolate (line, patt, rname, iname, "_FRAME", item->u.groupbox.box);
/*              sprintf (line, "#define I_%s_%s_BOX %d\n",rname, iname, item->u.groupbox.box);*/
                buf = doline (line, buf, &nbytes);
                interpolate (line, patt, rname, iname, "_LABEL", item->u.groupbox.label);
/*              sprintf (line, "#define I_%s_%s_LABEL %d\n",rname, iname, item->u.groupbox.label);*/
                buf = doline (line, buf, &nbytes);
                break;
            case AdjusterButton:
                interpolate (line, patt, rname, iname, "_DOWN", item->u.adjusterbutton.down);
/*              sprintf (line, "#define I_%s_%s_DOWN %d\n",rname, iname, item->u.adjusterbutton.down);*/
                buf = doline (line, buf, &nbytes);
                interpolate (line, patt, rname, iname, "_UP", item->u.adjusterbutton.up);
/*              sprintf (line, "#define I_%s_%s_UP %d\n",rname, iname, item->u.adjusterbutton.up);*/
                buf = doline (line, buf, &nbytes);
                break;
            }
        }

        if (any)
            buf = doline ("", buf, &nbytes);
    }

    return nbytes;
}


/*
 * Called from saveas module, for saving a whole Document
 */

error * genheader_saveas_cb (SaveAsReason reason, char **buf, int *size, void *closure)
{
    DocumentPtr doc = (DocumentPtr) closure;
    char *tag = "DefineFmt", *patt;

    patt = message_lookup (&msgs, tag);
    if (patt == tag)
        patt = "#define I_%w_%n %i";

dprintf("In genheader_saveas_cb %d\n" _ reason);
    switch (reason)
    {
    case SaveAsGetSize:
        *size = count_or_write (doc, NULL, patt);
        break;
    case SaveAsGetBlock:
        *buf = malloc (*size);
        if (*buf == NULL)
            return error_lookup("NoMem");
        count_or_write (doc, *buf, patt);
        break;
    case SaveAsFreeBlock:
        free (*buf);
        break;
    }
    return NULL;
}


/*
 * Called when !ResEd is used from the command-line with the generate header
 * only flag.
 */

error * genheader_only (FILE *file, DocumentPtr doc, char *patt)
{
    int size;
    char *tag = "DefineFmt", *buf;
    if (!patt || !*patt)
    {
        patt = message_lookup (&msgs, tag);
        if (patt == tag)
            patt = "#define I_%w_%n %i";
    }

    size = count_or_write (doc, NULL, patt);
    buf = malloc (size);
    if (!buf)
        return error_lookup ("NoMem");
    count_or_write (doc, buf, patt);
    fwrite (buf, 1, size, file);
    free (buf);
    return NULL;
}
